# jsb/plugs/gozer/quote.py
#
#

""" first ported gozerplugs plugin to JSONBOT. """

## jsb imports

from jsb.lib.persist import Persist
from jsb.lib.commands import cmnds
from jsb.lib.examples import examples
from jsb.utils.locking import lockdec
from jsb.utils.exception import handle_exception
from jsb.lib.aliases import getaliases

aliases = getaliases()

## basic imports

import random
import re
import time
import thread
import os
import types

## SQLAlchemy stuff

from jsb.database.alchemy import Base, create_session, trans, create_all, query
from datetime import datetime
from time import localtime   
from sqlalchemy import Column, String, Integer, Text, DateTime, ForeignKey, Sequence
import sqlalchemy as sa

## Quotes model

class Quotes(Base):
    __tablename__ = 'quotes'
    __table_args__ = {'useexisting': True }
    indx = Column('indx', Integer, primary_key=True)
    quote = Column('quote', Text, nullable=False)
    userhost = Column('userhost', String(255), nullable=False)
    createtime = Column('createtime', DateTime, nullable=False)
    nick = Column('nick', String(255), nullable=False)

    def __init__(self, quote, userhost, createtime, nick):
        self.quote = quote
        self.userhost = userhost
        self.createtime = createtime
        self.nick = nick

## QutoeDb class

class QuotesDb(object):

    """ quotes db interface """

    def size(self):
        """ return number of items """
        count = query(sa.func.count(Quotes.indx)).first()[0]
        return count

    @trans
    def add(self, session, nick, userhost, q, ttime=None):
        """ add a quote """
        if ttime:
            try:
                ttime = float(ttime)
            except TypeError:
                pass
            t = datetime.fromtimestamp(ttime)
        else: 
            t = datetime.now()
        quote = Quotes(q, userhost, t, nick)
        session.add(quote)
        session.commit()
        return quote.indx

    @trans
    def delete(self, session, quotenr):
        quote = session.query(Quotes).filter(Quotes.indx==quotenr).first()
        if quote:
             session.delete(quote)
             return 1

    def random(self):
        """ get random quote """
        result = query(Quotes.indx).all()
        indices = []
        if not result:
            return []
        for i in result:
            indices.append(i[0])
        if indices:
            idnr = random.choice(indices)
            return self.idquote(idnr)

    def idquote(self, quotenr):
        """ get quote by id """
        quote = query(Quotes).filter(Quotes.indx==quotenr).first()
        if quote:
            return quote

    def whoquote(self, quotenr):
        """ get who quoted the quote """
        quote = query(Quotes).filter(Quotes.indx==quotenr).first()
        if quote:
            return quote

    def last(self, nr=1):
        """ get last quote """ 
        result = query(Quotes).order_by(Quotes.indx.desc()).limit(nr)
        if result:
            return result

    def search(self, what):
        """ search quotes """
        result = query(Quotes).filter(Quotes.quote.like('%%%s%%' % what)).all()
        if result:
            return result

    def searchlast(self, what, nr):
        """ search quotes """
        result = query(Quotes).filter(Quotes.quote.like('%%%s%%' % what)).order_by(Quotes.indx.desc()).limit(nr)
        if result:
            return result

## defines

quotes = QuotesDb()
assert(quotes)

## init plugin

def init():
    create_all('quote')

## plugin size

def size():
    """ return number of quotes """
    return quotes.size()

## plugin search

def search(what, queue):
    """ search the quotes """
    logging.warn('searched for %s' % what)
    result = quotes.search(what)
    if result:
        for i in result: queue.put_nowait("#%s %s" % (i.indx, i.quote))

## quote-add command

def handle_quoteadd(bot, ievent):
    """ quote-add <txt> .. add a quote """
    if not ievent.rest: ievent.missing("<quote>") ; return
    idnr = quotes.add(ievent.nick, ievent.userhost, ievent.rest)
    ievent.reply('quote %s added' % idnr)

cmnds.add('quote-add', handle_quoteadd, ['USER', 'QUOTEADD'], allowqueue=False)
examples.add('quote-add', 'quote-add <txt> .. add quote', 'quote-add mekker')

## quote-who command

def handle_quotewho(bot, ievent):
    """ quote-who <nr> .. show who added a quote """
    try: quotenr = int(ievent.args[0])
    except IndexError: ievent.missing("<nr>") ; return
    except ValueError: ievent.reply("argument must be an integer") ; return
    result = quotes.whoquote(quotenr)
    if not result: ievent.reply('no who quote data available') ; return
    if result.createtime:
        if type(result.createtime) == types.LongType:
            ievent.reply('quote #%s was made by %s on %s' % (quotenr, result.nick, datetime.fromtimestamp(result.createtime).ctime()))
        else:
            ievent.reply('quote #%s was made by %s on %s' % (quotenr, result.nick, result.createtime.ctime()))
    else: ievent.reply('quote #%s was made by %s' % (quotenr, result.nick))

cmnds.add('quote-who', handle_quotewho, ['USER', 'WEB', 'CLOUD', 'ANONQUOTE'])
examples.add('quote-who', 'quote-who <nr> .. show who quote <nr>', 'quote-who 1')

## quote-del command

def handle_quotedel(bot, ievent):
    """ quote-del <nr> .. delete quote by id """
    try: quotenr = int(ievent.args[0])
    except IndexError: ievent.missing('<nr>') ; return
    except ValueError: ievent.reply('argument needs to be an integer') ; return
    if quotes.delete(quotenr): ievent.reply('quote %s deleted' % quotenr)
    else: ievent.reply("can't delete quote with nr %s" % quotenr)

cmnds.add('quote-del', handle_quotedel, ['QUOTEDEL', 'OPER', 'QUOTE'])
examples.add('quote-del', 'quote-del <nr> .. delete quote', 'quote-del 2')

## quote-last comamnd

def handle_quotelast(bot, ievent):
    """ quote-last .. show last quote """
    search = ""
    try: (nr, search) = ievent.args ; nr = int(nr)  
    except ValueError:
        try: nr = ievent.args[0] ; nr = int(nr)
        except (IndexError, ValueError):
            nr = 1
            try: search = ievent.args[0]
            except IndexError: search = ""
    if nr < 1 or nr > 4: ievent.reply('nr needs to be between 1 and 4') ; return
    search = re.sub('^d', '', search)
    if search: quotelist = quotes.searchlast(search, nr)
    else: quotelist = quotes.last(nr)
    if quotelist != None:
        for quote in quotelist:
            try:
                from jsb.plugs.gozer.karma import karma
                qkarma = karma.get('quote %s' % quote.indx)
                if qkarma: ievent.reply('#%s (%s) %s' % (quote.indx, qkarma, quote.quote))
                else: ievent.reply('#%s %s' % (quote.indx, quote.quote))
            except (ImportError, AttributeError): ievent.reply('#%s %s' % (quote.indx, quote.quote))
    else: ievent.reply("can't fetch quote")

cmnds.add('quote-last', handle_quotelast, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-last', 'show last quote', 'quote-last')

## quote-2 command

def handle_quote2(bot, ievent):
    """ quote-2 .. show 2 random quotes """
    quote = quotes.random()
    if quote:
        try:
            from jsb.plugs.gozer.karma import karma
            qkarma = karma.get('quote %s' % quote.indx)
            ievent.reply('#%s (%s) %s' % (quote.indx, qkarma, quote.quote))
        except: ievent.reply('#%s %s' % (quote.indx, quote.quote))
    else: ievent.reply('no quotes yet') ; return
    quote = quotes.random()
    if quote:
        qkarma = karma.get('quote %s' % quote.indx)
        if qkarma: ievent.reply('#%s (%s) %s' % (quote.indx, qkarma, quote.quote))
        else: ievent.reply('#%s %s' % (quote.indx, quote.quote))

cmnds.add('quote-2', handle_quote2, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-2', 'quote-2 .. show 2 random quotes', 'quote-2')

## quote-id

def handle_quoteid(bot, ievent):
    """ quote-id <nr> .. show quote by id """
    try: quotenr = int(ievent.args[0])
    except IndexError: ievent.missing('<nr>') ; return
    except ValueError: ievent.reply('argument must be an integer') ;return
    quote = quotes.idquote(quotenr)
    if quote:
        try:
            from jsb.plugs.gozer.karma import karma
            qkarma = karma.get('quote %s' % quote.indx)
            ievent.reply('#%s (%s) %s' % (quote.indx, qkarma or 0, quote.quote))
        except: ievent.reply('#%s %s' % (quote.indx, quote.quote))
    else: ievent.reply("can't fetch quote with id %s" % quotenr)

cmnds.add('quote-id', handle_quoteid, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-id', 'quote-id <nr> .. get quote <nr>', 'quote-id 2')

## quote command

def handle_quote(bot, ievent):
    """ quote .. show random quote """
    quote = quotes.random()
    if quote:
        try:
            from jsb.plugs.gozer.karma import karma
            qkarma = karma.get('quote %s' % quote.indx)
            ievent.reply('#%s (%s) %s' % (quote.indx, qkarma or 0, quote.quote))
        except: ievent.reply('#%s %s' % (quote.indx, quote.quote))
    else: ievent.reply('no quotes yet')

cmnds.add('quote', handle_quote, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote', 'show random quote', 'quote')

def handle_quotesearch(bot, ievent):
    """ quote-search <txt> .. search quotes """
    if not ievent.rest: ievent.missing('<item>') ; return
    else: what = ievent.rest ; nrtimes = 3
    result = quotes.search(what)
    if result:
        if ievent.queues:
            res = []
            for quote in result: res.append('#%s %s' % (quote.indx, quote.quote))
            ievent.reply(res)
            return            
        if nrtimes > len(result): nrtimes = len(result)
        randquotes = random.sample(result, nrtimes)
        for quote in randquotes:
            try:
                from jsb.plugs.gozer.karma import karma
                qkarma = karma.get('quote %s' % quote.indx)
                ievent.reply('#%s (%s) %s' % (quote.indx, qkarma or 0, quote.quote))
            except: ievent.reply("#%s %s" % (quote.indx, quote.quote))
    else: ievent.reply('no quotes found with %s' % what)

cmnds.add('quote-search', handle_quotesearch, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-search', 'quote-search <txt> .. search quotes for <txt>', 'quote-search bla')

## quote-count command

def handle_quotescount(bot, ievent):
    """ quote-count .. show number of quotes """
    ievent.reply('quotes count is %s' % quotes.size())

cmnds.add('quote-count', handle_quotescount, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-count', 'count nr of quotes', 'quote-count')

## quote-good command

def handle_quotegood(bot, ievent):
    """ show top ten positive karma """
    try:
        from jsb.plugs.gozer.karma import karma
        result = karma.quotegood(limit=10)
        if result:
            resultstr = ""
            for i in result:
                if i[1] > 0:
                    resultstr += "%s: %s " % (i[0], i[1])
            ievent.reply('quote goodness: %s' % resultstr)
        else:
            ievent.reply('quote karma void')
    except Exception, ex: ievent.reply("error: %s" % str(ex))

cmnds.add('quote-good', handle_quotegood, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-good', 'show top 10 quote karma', 'quote-good')

## quote-bad command

def handle_quotebad(bot, ievent):
    """ show top ten negative karma """
    try:
        from jsb.plugs.gozer.karma import karma
        result = karma.quotebad(limit=10)
        if result:
            resultstr = ""
            for i in result:
                if i[1] < 0: resultstr += "%s: %s " % (i[0], i[1])
            ievent.reply('quote badness: %s' % resultstr)
        else: ievent.reply('quote karma void')
    except Exception, ex: ievent.reply("error: %s" % str(ex))

cmnds.add('quote-bad', handle_quotebad, ['USER', 'WEB', 'ANONQUOTE', 'CLOUD'])
examples.add('quote-bad', 'show lowest 10 quote karma', 'quote-bad')
